#include <QDebug>
#include <QProcess>
#include <QApplication>
#include <QVariant>
#include <QTcpSocket>
#include <QStringBuilder>
#include <QMessageBox>
#include <QSettings>
#include "RopeProject.h"
#include "RopeFile.h"
#include "XMLRPC.h"
#include "Include/Settings.h"
#include "Project.h"

namespace Plugins
{

RopeProject::RopeProject():
    _ip("127.0.0.1"),
    _port(9999)
{
    _proc = new QProcess();
    connect(_proc, SIGNAL(readyReadStandardError()), SLOT(readyError()));

    QString path = QApplication::applicationDirPath() % "/python3/RopeSrv.py";
    if (!QFile::exists(path))
        path = "/usr/share/pynoto/python3/RopeSrv.py";


    _proc->start(Project::currentInstance()->python(), QStringList() << path);
    connect(_proc, SIGNAL(error(QProcess::ProcessError)), SLOT(onRunError(QProcess::ProcessError)));

    _proc->waitForStarted(1000);
    if (_proc->state() == QProcess::Running){
        _proc->waitForReadyRead();
        QStringList out = QString(_proc->readAll()).split(' ');
        if (out.length() == 2){
            _ip = out[0];
            _port = out[1].toInt();
        }
    } else {
        delete _proc;
        _proc = NULL;
    }
}

RopeProject::~RopeProject()
{
    qDebug() << "Terminate process";
    if (_proc)
        _proc->write("shut\n");
    qDeleteAll(_files);
    if (_proc){
        _proc->terminate();
        _proc->waitForFinished();
        delete _proc;
    }
}

void RopeProject::onRunError(QProcess::ProcessError err)
{
    if (err == QProcess::FailedToStart){
        QMessageBox::critical(NULL, tr("Python error"), tr("Error while run of python interpreter"));
        _proc->terminate();
    }
}

IRopeFile* RopeProject::openFile(const QString & fileName)
{
    _files[fileName] = new RopeFile(fileName, this);
    return _files[fileName];
}

void RopeProject::closeFile(const QString & fileName)
{
    if (_files.contains(fileName)){
        delete _files.take(fileName);
    }
}

void RopeProject::revalidate(const QString & path, const QString & mainScript, const QString& projectPath)
{
    if (!_proc)
        return;

    QSettings set;
    QVariantList list;
    list << path << mainScript << projectPath << QFileInfo(set.fileName()).absoluteDir().path()+"/classes";
    makeRequest("revalidate", list, this, SLOT(onProjectRevalidated()));
    _loop.exec();
}

void RopeProject::readyError()
{
    qDebug() << "ERR:" << _proc->readAllStandardError();
}

void RopeProject::initProject(const QString & path, const QString & mainScript, const QString& projectPath)
{
    if (!_proc)
        return;

    QSettings set;
    QVariantList list;
    list << path << mainScript << projectPath << QFileInfo(set.fileName()).absoluteDir().path()+"/classes";
    makeRequest("initProject", list, this, SLOT(onProjectInited()));
    _loop.exec();
}

void RopeProject::onProjectInited()
{
    XMLRPC::readSocket(qobject_cast<QTcpSocket*>(sender()));
    _loop.exit();
}

void RopeProject::onProjectRevalidated()
{
    XMLRPC::readSocket(qobject_cast<QTcpSocket*>(sender()));
    _loop.exit();
    foreach(RopeFile * file, _files.values()){
        file->errorsList();
    }
}

void RopeProject::makeRequest(const QString & methodName, const QVariantList & params, QObject * reciever, const char * slot)
{
    if (!_proc)
        return;
    if (_port == 9999)
        return;

    QTcpSocket *soc = new QTcpSocket(this);
    soc->connectToHost(_ip, _port);
    soc->waitForConnected();
    soc->setProperty("method", methodName);
    connect(soc, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(onError(QAbstractSocket::SocketError)));
    if (reciever && slot){
        connect(soc, SIGNAL(readyRead()), reciever, slot);
    }
    soc->write(XMLRPC::prepareRequest(methodName, params).toUtf8());
}

void RopeProject::classNames(const QString & prefix)
{
    makeRequest("classNames", QVariantList() << prefix, this, SLOT(onClassList()));
}

void RopeProject::onClassList()
{
    QStringList list = XMLRPC::parseResponce<QStringList>(XMLRPC::readSocket(qobject_cast<QTcpSocket*>(sender())));
    emit classListComplete(list);
}

void RopeProject::onError(QAbstractSocket::SocketError err)
{
    QTcpSocket * soc = qobject_cast<QTcpSocket*>(sender());
    qDebug() << "Error:" << soc->errorString() << soc->property("method");
}

}
